package com.nulldev.util.web.YouTubeExtractor.signatures;

import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

import com.nulldev.util.JVM.Arguments;
import com.nulldev.util.VariableAPI.StringsUtil;
import com.nulldev.util.data.Variables;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.YouTubeExtractor.YouTubeExtractor;
import com.nulldev.util.web.YouTubeExtractor.YouTubeExtractorConstants;

public class SignatureUpdates {

	private static final Logger log = LoggerFactory
			.getLoggerD(Arguments.hasArgument("--debug", "-debug", "--trace", "--SignatureUpdates.debug", "--SignatureExtractor.debug"));

	private static final AtomicReference<String> CURRENT_PLAYER_URL = new AtomicReference<String>();

	private static final boolean CLEAN_URL_CHARS = Arguments.hasArgument("--SignatureExtractor.cleanUrlChars", "--SignatureUpdates.cleanUrlChars");

	private static final String PLAYER_URL_PATTERN1 = Pattern.quote("\\/");

	public static String getPlayerURL(final String page) {
		Variables.requireNonNull(page, "page");
		String o = YouTubeExtractorConstants.find_value(page, "PLAYER_JS_URL");
		if (o == null || o.isEmpty())
			o = YouTubeExtractorConstants.find_value_alt(page, "PLAYER_JS_URL");
		if (o == null || o.isEmpty())
			o = StringsUtil.substringBetweenO(page, "\"PLAYER_JS_URL\":\"", "\",\"");
		if (o == null || o.isEmpty())
			o = YouTubeExtractorConstants.find_value(page, "player_js_url");
		if (o == null || o.isEmpty())
			o = YouTubeExtractorConstants.find_value_alt(page, "player_js_url");
		if (o == null || o.isEmpty())
			o = StringsUtil.substringBetweenO(page, "\"player_js_url\":\"", "\",\"");
		if (o != null) {
			o = o.replaceAll(PLAYER_URL_PATTERN1, "/");
			o = StringsUtil.substringBetweenO(o, "\"", "\",\"");
		}
		if (o == null)
			throw new NullPointerException("Failed to get player URL! [o == null!]");
		log.debug("getPlayerURL::fromData-pre: " + o);
		if (o.contains("\"});"))
			o = o.substring(0, o.indexOf("\"});"));
		if (o.contains("\"});ytcfg"))
			o = o.substring(0, o.indexOf("\"});ytcfg"));
		if (o.contains("\"});"))
			o = o.substring(0, o.indexOf("\"});"));
		log.debug("getPlayerURL::fromData: " + o);
		if (CLEAN_URL_CHARS)
			o = StringsUtil.cleanInvalidCharacters(o);
		else
			o = o.trim();
		if (o.startsWith("https://")) {
			return o;
		} else {
			if (o.startsWith("/yts/"))
				return "https://s.ytimg.com" + o;
			if (o.startsWith("/s/"))
				return "https://www.youtube.com" + o;
			return "https://s.ytimg.com/yts/jsbin/player_" + o;
		}
	}

	public static String getVariantsChecksum(final String htmlPage) {
		if (htmlPage == null || htmlPage.isEmpty())
			return null;
		String variantsChecksum = StringsUtil.substringBetweenO(htmlPage, "\"VARIANTS_CHECKSUM\":\"", "\",");
		if (variantsChecksum != null && (variantsChecksum.contains("style=") || variantsChecksum.contains(" "))) {
			variantsChecksum = null;
		}
		if (variantsChecksum == null) {
			variantsChecksum = StringsUtil.substringBetweenO(htmlPage, ",\"VARIANTS_CHECKSUM\":\"", "\",\"");
			if (variantsChecksum == null) {
				variantsChecksum = StringsUtil.substringBetweenO(htmlPage, ",'VARIANTS_CHECKSUM': \"", "\",'");
			}
			if (variantsChecksum == null) {
				variantsChecksum = YouTubeExtractorConstants.find_value(htmlPage, "VARIANTS_CHECKSUM");
			}
			if (variantsChecksum == null) {
				variantsChecksum = YouTubeExtractorConstants.find_value_alt(htmlPage, "VARIANTS_CHECKSUM");
			}
		}
		if (variantsChecksum != null && variantsChecksum.contains("\"});")) {
			variantsChecksum = variantsChecksum.substring(0, variantsChecksum.indexOf("\"});"));
		}
		return variantsChecksum;
	}

	public static boolean requiresUpdate(String playerID, String variantsChecksum) {
		playerID = StringsUtil.cleanInvalidCharacters(playerID);
		variantsChecksum = StringsUtil.cleanInvalidCharacters(variantsChecksum);
		if (!YouTubeExtractor.extractor.hasCachedItem()) {
			log.debug("requiresUpdate() -> Triggered via missing SignatureExtractor.");
			return false;
		}
		if (CURRENT_PLAYER_URL.get() != null && !playerID.equalsIgnoreCase(CURRENT_PLAYER_URL.get())) {
			log.debug("requiresUpdate() -> Triggered via PLAYER_ID_MISMATCH.");
			return true;
		}
		if (YouTubeExtractorConstants.ENABLE_VARIANTS_CHECKSUM) {
			/* Trigger if there are no variants checksum present. */
			if (variantsChecksum == null)
				return true;

			if (variantsChecksum != null && variantsChecksum.equalsIgnoreCase("ml style=")) {
				return false;
			}
			// This shouldn't reach anymore since VARIANTS_CHECKSUM is no more.
			if (!variantsChecksum.equalsIgnoreCase(YouTubeExtractorConstants.VARIANTS_CHECKSUM) && YouTubeExtractorConstants.ENABLE_VARIANTS_CHECKSUM) {
				log.debug("requiresUpdate() -> Triggered via VARIANTS_CHECKSUM_MISMATCH.");
				log.debug("provided-checksum: " + variantsChecksum);
				log.debug("local-checksum: " + YouTubeExtractorConstants.VARIANTS_CHECKSUM);
				return true;
			}
		}
		return false;
	}

	public static String getCachedPlayerURL() {
		return CURRENT_PLAYER_URL.get();
	}

	public static void setCachedPlayerURL(final String playerURL) {
		log.debug("setCachedPlayerURL() -> " + playerURL);
		CURRENT_PLAYER_URL.lazySet(Variables.requireNonNullObject(playerURL, "playerURL"));
	}
}
